package cn.szsys.integration.util.listener;

import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author Ryan
 * @since 2025-06-18
 **/
@Slf4j
public class OkHttpListener extends EventListener {
    private long callStart;
    private long dnsStart;
    private long dnsEnd;
    private long connectStart;
    private long connectEnd;
    private long secureConnectStart;
    private long secureConnectEnd;
    private long sentHeaderStart;
    private long sentHeaderEnd;
    private long sentRequestStart;
    private long sentRequestEnd;
    private long receiveHeaderStart;
    private long receiveHeaderEnd;
    private long receiveResponseStart;
    private long receiveResponseEnd;

    @Override
    public void callStart(@NotNull Call call) {
        callStart = System.nanoTime();
    }

    @Override
    public void dnsStart(@NotNull Call call, @NotNull String domainName) {
        dnsStart = System.nanoTime();
    }

    @Override
    public void dnsEnd(@NotNull Call call, @NotNull String domainName, @NotNull List<InetAddress> inetAddressList) {
        dnsEnd = System.nanoTime();
    }

    @Override
    public void connectStart(@NotNull Call call, @NotNull InetSocketAddress inetSocketAddress, @NotNull Proxy proxy) {
        connectStart = System.nanoTime();
    }

    @Override
    public void secureConnectStart(@NotNull Call call) {
        secureConnectStart = System.nanoTime();
    }

    /**
     * @param call      call
     * @param handshake handshake
     */
    @Override
    public void secureConnectEnd(@NotNull Call call, @Nullable Handshake handshake) {
        secureConnectEnd = System.nanoTime();
    }

    @Override
    public void connectEnd(@NotNull Call call, @NotNull InetSocketAddress inetSocketAddress, @NotNull Proxy proxy, Protocol protocol) {
        connectEnd = System.nanoTime();
    }

    @Override
    public void requestHeadersStart(@NotNull Call call) {
        sentHeaderStart = System.nanoTime();
    }

    @Override
    public void requestHeadersEnd(@NotNull Call call, @NotNull Request request) {
        sentHeaderEnd = System.nanoTime();
    }

    @Override
    public void requestBodyStart(@NotNull Call call) {
        // 写入请求体开始
        sentRequestStart = System.nanoTime();
    }

    @Override
    public void requestBodyEnd(@NotNull Call call, long byteCount) {
        sentRequestEnd = System.nanoTime();
    }

    @Override
    public void responseHeadersStart(@NotNull Call call) {
        receiveHeaderStart = System.nanoTime();
    }

    @Override
    public void responseHeadersEnd(@NotNull Call call, @NotNull Response response) {
        receiveHeaderEnd = System.nanoTime();
    }

    @Override
    public void responseBodyStart(@NotNull Call call) {
        // 响应体开始接收
        receiveResponseStart = System.nanoTime();
    }

    @Override
    public void responseBodyEnd(@NotNull Call call, long byteCount) {
        receiveResponseEnd = System.nanoTime();
    }

    /**
     * @param call
     * @param connection
     */
    @Override
    public void connectionReleased(@NotNull Call call, @NotNull Connection connection) {
        super.connectionReleased(call, connection);
    }

    @Override
    public void callEnd(@NotNull Call call) {
        long callDuration = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - callStart);
        long dnsDuration = TimeUnit.NANOSECONDS.toMillis(dnsEnd - dnsStart);
        long connectDuration = TimeUnit.NANOSECONDS.toMillis(connectEnd - connectStart);
        long secureConnectDuration = TimeUnit.NANOSECONDS.toMillis(secureConnectEnd - secureConnectStart);
        long requestDuration = TimeUnit.NANOSECONDS.toMillis(sentRequestEnd - sentRequestStart);
        long requestHeaderDuration = TimeUnit.NANOSECONDS.toMillis(sentHeaderEnd - sentHeaderStart);
        long responseDuration = TimeUnit.NANOSECONDS.toMillis(receiveResponseEnd - receiveResponseStart);
        long responseHeaderDuration = TimeUnit.NANOSECONDS.toMillis(receiveHeaderEnd - receiveHeaderStart);
        log.info("Call Duration: {}ms, DNS Duration: {}ms, Connect Duration: {}ms, SecureConnectDuration: {}ms," +
                        "Request Duration: {}ms, RequestHeader Duration: {}ms, Response Duration: {}ms, " +
                        "ResponseHeader Duration: {}ms", callDuration, dnsDuration, connectDuration, secureConnectDuration, requestDuration,
                requestHeaderDuration, responseDuration, responseHeaderDuration);
    }

    @Override
    public void callFailed(@NotNull Call call, IOException e) {
        log.info("Call Failed: {}", e.getMessage());
    }

    /**
     * 私有构造，通过工厂方法创建
     * @author Ryan
     */
    private OkHttpListener() {
    }

    /**
     * 工厂方法
     */
    public static Factory FACTORY = request -> new OkHttpListener();

}
